//------------------------------------------------------------------------------
// Fichiers d'ent�te utilis�s
//------------------------------------------------------------------------------
#include "ConvolutionOperator.hpp"
#include "Region.hpp"
#include "Orientation.hpp"
#include <math.h>
#include "Tools/LoggerFile.hpp"
#include <iostream>

//------------------------------------------------------------------------------
// Définition de constantes
//------------------------------------------------------------------------------

namespace ImageAnalysis
{

	//----------------------------------------------------------------------
	// Constructeur
	//----------------------------------------------------------------------
	ConvolutionOperator::ConvolutionOperator( GrayImage* image, Gradiant* gradiant, Mask** masks, int nbMask ):
	currentImage(image),
	currentGradiant(gradiant),
	convolutionMask(masks),
	numberOfMask(nbMask)
	{	
	
	}

	//----------------------------------------------------------------------
	// Destructeur
	//----------------------------------------------------------------------
	ConvolutionOperator::~ConvolutionOperator( )
	{
	
	}
	
	//----------------------------------------------------------------------
	// 
	//----------------------------------------------------------------------
	void ConvolutionOperator::Process( )
	{	
			
		int masksSize        = convolutionMask[0]->Size;
		unsigned int coefMax = convolutionMask[0]->GetMaximumNormalizeCoefficient();
		int offset           = (masksSize-1)/2;
        	int numberOfValues   = masksSize*masksSize;
	    	unsigned char* normsCandidate 		 = new unsigned char[numberOfMask];
		unsigned char* orientationsCandidate = new unsigned char[numberOfMask];
		
		int imageWidth  = currentImage->GetWidth();
		int imageHeight = currentImage->GetHeight();
		
		for( int i=offset; i < (imageWidth-offset); ++i )
		{
			for( int j=offset; j < (imageHeight-offset); ++j )
			{
				// Calcul de l'index du pixel courant
				int index = i + j*imageWidth ;

				int* region = currentImage->GetPixelNeighborHood(index,offset);

				// Pour tous les masques
				for( int m=0; m<numberOfMask; ++m)
				{
                    			// Calcule de la valeur du gradient (cette valeur peut être supérieur à 255 ou être négative)
					int fullValue = 0;
					for(int k=0; k<numberOfValues; ++k)
					{
						fullValue += *currentImage->GetPixel( region[k] ) * convolutionMask[m]->Value[k];
					}

					// Redressement de la valeur si elle est négative (cas où l'on passe d'une zone clair à une zone foncée)
					if( fullValue < 0 )
					{   fullValue = -fullValue; }
			
					// Normalisation de la valeur en fonction des coefficients du mask
					fullValue /= coefMax;
					normsCandidate[m] = (unsigned char)fullValue;
				}
				
				if(numberOfMask == 2)
				{
					unsigned char avg = (unsigned char)(sqrt((normsCandidate[0]*normsCandidate[0])+(normsCandidate[1]*normsCandidate[1])));
					currentGradiant->SetGradiantNorm(index, avg );
					if( normsCandidate[0] == 0 )
					{	
						if( normsCandidate[1] == 0 )
						{ 	currentGradiant->SetGradiantOrientation(index,0.0f);}
						else
						{ 	currentGradiant->SetGradiantOrientation( index, 90.0f/*Orientation::ConvertDirectionToAngle(convolutionMask[1]->Direction)*/ ); }
					}	
					else
					{	
						//double value = 180.0f/M_PI * atan( normsCandidate[1] / normsCandidate[0] );
						currentGradiant->SetGradiantOrientation( index, 180.0f/M_PI * atan((float)normsCandidate[1]/(float)normsCandidate[2]) );
					}
				}
				else
				{
					int maximumIndex;
					currentGradiant->SetGradiantNorm(index, (unsigned char)findMax(normsCandidate, numberOfMask, maximumIndex) );
					currentGradiant->SetGradiantOrientation( index, Orientation::ConvertDirectionToAngle(convolutionMask[maximumIndex]->Direction));
				}
				
				delete region;
			}
		}

		delete orientationsCandidate;
		delete normsCandidate;
	}
	
	//----------------------------------------------------------------------
	//
	//----------------------------------------------------------------------
	unsigned char ConvolutionOperator::findMax(unsigned char* tableToStudy, int tableSize, int& indexMax)
	{
		unsigned char max = tableToStudy[0];
		indexMax = 0;
		for(int i=1; i<tableSize;++i)
		{
			if(tableToStudy[i]>max)
            		{   
				max = tableToStudy[i]; 		
				indexMax = i;
			}
		}
		return max;
	}
}

